package com.fm.financemanage.shiro;


import com.fm.financemanage.filter.MyAuthenticationFilter;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSessionStorageEvaluator;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 权限配置加载
 */
@Configuration
public class ShiroConfig {


//    @Autowired
//    private MyAuthenticationFilter authenticationFilter;


    /**
     * 缓存管理器 使用Ehcache实现
     */
    @Bean
    public EhCacheManager getEhCacheManager() {
        EhCacheManager ehcacheManager = new EhCacheManager();
        ehcacheManager.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml");
        return ehcacheManager;
    }


    /**
     * 自定义Realm
     */
    @Bean
    public ShiroUserRealm userRealm(EhCacheManager ehCacheManager) {
        ShiroUserRealm shiroUserRealm = new ShiroUserRealm();
        /*
         *  指定shiro在校验密码的时候使用什么加密方式,在不指定的时候会使用默认的SimpleCredentialsMatcher 进行密码对比
         *  这里指定md5加密方式进行对比(默认不加盐和 散列次数一次)
         */
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        shiroUserRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        // 指定用户获得授权信息之后使用的缓存管理器,不指定代表用户不使用就会导致每次访问需要权限方法的时候都请求授权 使效率变低
        shiroUserRealm.setCacheManager(ehCacheManager);
        return shiroUserRealm;
    }

    /**
     * 安全管理器
     */
    @Bean
    public SecurityManager securityManager(ShiroUserRealm shiroUserRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        securityManager.setSessionManager(mySessionManager());
        // 设置realm.
        securityManager.setRealm(shiroUserRealm);
        // 如果代码内使用了异步方法 则需要绑定到线程内部中
        ThreadContext.bind(securityManager);
        return securityManager;
    }

    /**
     * 创建SessionManager管理器,设置SessionIdUrlRewritingEnabled为false
     * 作用是当跳转到指定的登录接口时不会携带sessionId
     **/
    @Bean
    public DefaultWebSessionManager mySessionManager() {
        DefaultWebSessionManager defaultSessionManager = new DefaultWebSessionManager();
        //将sessionIdUrlRewritingEnabled属性设置成false
        defaultSessionManager.setSessionIdUrlRewritingEnabled(false);
        return defaultSessionManager;
    }


    /**
     * Shiro过滤器配置
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // Shiro的核心安全接口,这个属性是必须的
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, Filter> filterMap = shiroFilterFactoryBean.getFilters();
        filterMap.put("authc", new MyAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        // 身份认证失败，跳转登录页面(会访问配置的登录页面接口)
        //  由于我们自己实现了过滤器所以在isAccessAllowed 不会重定向登录地址 所以这边暂时不进行配置
        // shiroFilteFrFactoryBean.setLoginUrl("/sys/user/login");
        // 权限认证失败，则跳转到指定页面
        //shiroFilterFactoryBean.setUnauthorizedUrl("/api/user/d");
        // shiroFilterFactoryBean.setSuccessUrl("/api/user/dd");
        // Shiro连接约束配置，即过滤链的定义
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 对静态资源设置匿名访问
        filterChainDefinitionMap.put("/favicon.ico**", "anon");
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/html/**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/docs/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/ajax/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        //放行Swagger2页面，需要放行这些
        filterChainDefinitionMap.put("/doc.html", "anon");
        filterChainDefinitionMap.put("/swagger/**", "anon");
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**", "anon");
        filterChainDefinitionMap.put("/v2/**", "anon");
        filterChainDefinitionMap.put("/static/**", "anon");
        // 开放性接口，不需要鉴权
        filterChainDefinitionMap.put("/openapi/**", "anon");

        // 退出logout地址
        filterChainDefinitionMap.put("/logout", "logout");
        // 不需要拦截的访问
        filterChainDefinitionMap.put("/sys/user/login", "anon");
        // 所有请求需要认证
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }


    /**
     * 开启shiro 的注解支持
     **/
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * session会话管理器 禁用session会话
     **/
    @Bean
    protected SessionStorageEvaluator sessionStorageEvaluator() {
        DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return sessionStorageEvaluator;
    }


}
